package com.cgg.java8.ch01;

import com.cgg.java8.ch01.predicates.ApplePredicate;
import com.cgg.java8.ch01.predicates.RedColorPredicate;
import com.cgg.java8.ch01.predicates.WeightPredicate;
import com.cgg.java8.entity.Apple;
import com.cgg.java8.utils.Utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author Xiecheng create on 2021/9/14
 */
public class Demo02 {
    public static void main(String[] args) {
        List<Apple> apples = Arrays.asList(
                new Apple("green", 70),
                new Apple("red", 90),
                new Apple("pink", 160),
                new Apple("yellow", 250)
        );

        // 筛选红色苹果
        Utils.printListAsJson(filterApples(apples, new RedColorPredicate()));

        // 筛选重量超过150的苹果
        Utils.printListAsJson(filterApples(apples, new WeightPredicate()));

        // 至此, 已经比Demo01中的代码, 灵活了许多. 但是还有一个很大的问题, 就是不同的判断条件, 需要写不同的predicate.
        // 并将predicate的filter实现, 传递到filterApples()方法中.
        // 在jdk8之前, 我们还可以使用匿名内部类来省去创建多个ApplePredicate的方法, 如下:
        // 筛选颜色不为pink, 且重量大于250g的苹果
        Utils.printListAsJson(filterApples(apples, new ApplePredicate() {
            @Override
            public boolean test(Apple apple) {
                return !"pink".equals(apple.getColor()) && apple.getWeight() > 150;
            }
        }));

        // 可以用lambda来简化上面的写法.筛选颜色不为 green的, 重量小于100g的苹果
        Utils.printListAsJson(filterApples(apples, apple -> !"green".equals(apple.getColor())
                && apple.getWeight() < 100));

        // 接下来还可以进一步的抽象, 因为ApplePredicate只能适用于Apple. 所以我们做一次抽象
        // 先创建接口Predicate. 然后编写方法filter
        // 尝试筛选偶数
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        Utils.printListAsJson(filter(numbers, i -> i % 2 ==0));

        // 到这里, 我们自己写了一种通过行为参数化传递代码的例子. 其实jdk提供的api中, 也有这样的case. 详见Demo03
    }

    /**
     * 根据自定义predicate, 进行苹果的筛选
     *
     * @param apples
     * @param predicate
     * @return
     */
    private static List<Apple> filterApples(List<Apple> apples, ApplePredicate predicate) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : apples) {
            if (predicate.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }

    /**
     * 抽象后的filter方法, 进行任意对象的筛选
     *
     * @param elements
     * @param predicate
     * @param <T>
     * @return
     */
    private static<T> List<T> filter(List<T> elements, Predicate<T> predicate) {
        List<T> result = new ArrayList<>();
        for (T element : elements) {
            if (predicate.test(element)) {
                result.add(element);
            }
        }
        return result;
    }
}
